package com.resafety.hop.weekly.model.statistics.entity.vo;

import com.resafety.hop.weekly.common.RestResult;
import org.apache.catalina.User;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;

/**
 * 考勤管理业务层接口
 * @author huang
 * @since 2021-11-03
 */
public class AttendanceServiceImpl {

    private static final int MORNING_HOUR = 12;
    private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * TODO 打卡记录，前端只需调用接口即可，后台自动处理上下班、重复打卡、补卡（仅支持当天补卡）等操作
     * @param request 请求报文
     */
    @Transactional(rollbackFor = Exception.class)
    public RestResult<Object> clockIn(HttpServletRequest request){

        // sep1：获取登录用户信息略过，一般根据请求头信息获取（request）
        User user = new User();

        // sep2：用户合法性校验

        // sep3：合法性通过，获取用户信息
        Long userId = user.getId();

        // sep3：打卡逻辑
        // 当天打卡记录
        ClockInRecord record = userClockInMapper.getCurrentDayClockInByUserId(userId);

        // 当天还未打卡（不管什么时候都是上班打卡）
        if (record == null){
            record = new ClockInRecord();
            // 设置上班打卡时间，其余字段忽略，下班打卡时间为空
            record.setMorningClockInTime(LocalDateTime.now());
            int result = userClockInMapper.insertRecord(userId);
            // 如果入库失败，则日志记录，并 return
        }

        // 当前打过卡，再次打卡的话，根据时间自动判断上下班卡（主要目的是讲业务放在后台，不让前端处理，提高系统健壮性，简单避免恶意接口攻击）
        int hour = LocalDateTime.now().getHour();

        // 当前时间未超过中午 12:00 ，视为上班卡，并且打卡记录存在，只需更新上班卡时间
        if (hour <= MORNING_HOUR){
            // 重复打卡，更新打卡时间
            int result = userClockInMapper.updateMorningClockInTimeByUserId(userId);
            // 如果更新失败，则日志记录，并 return
        } else {
            // 超过中午 12:00，视为下班卡
            if (record.getAfternoonClockInTime() != null){
                // 重复打卡，更新下午打卡时间，简单日志记录
            }
            // 更新下班卡时间
            int result = userClockInMapper.updateAfternoonClockInTimeByUserId(userId);
            // 如果入库失败，则日志记录，并 return
        }

        return RestResult.builder().code(-1).msg("服务器繁忙，请联系管理员");
    }

    /**
     * TODO 隔天补卡，上班：09:00，下班： 18:00
     * @param request 请求报文
     * @param date 日期
     */
    public RestResult<Object> makeUpClockIn(HttpServletRequest request, LocalDate date){
        // sep1：获取登录用户信息略过，一般根据请求头信息获取（request）
        User user = new User();

        // sep2：用户合法性校验

        // sep3：合法性通过，获取用户信息
        Long userId = user.getId();

        // 查询指定日期打卡记录，sql 根据传入时间进行指定天查询记录
        ClockInRecord record = userClockInMapper.getOneDayClockInByUserIdAndDate(userId, date);

        // 判断隔天补卡类型，全天、上班卡、下班卡
        if (record == null){
            // TODO 补全天
            record = new ClockInRecord();
            // 设置上班打卡时间，其余字段忽略，下班打卡时间为空
            record.setMorningClockInTime(LocalDateTime.parse("2021-09-01 09:00:00"));
            record.setAfternoonClockInTime(LocalDateTime.parse("2021-09-01 09:00:00"));
            // DB 操作
            return RestResult.success("补卡成功，类型为全天");
        } else if (record.getMorningClockInTime() == null){
            // TODO 补上班卡
            record.setMorningClockInTime(LocalDateTime.parse("2021-09-01 09:00:00"));
            // DB 操作
            return RestResult.success("补卡成功，类型为上班卡");
        } else if (record.getAfternoonClockInTime() == null){
            // TODO 补下班卡
            record.setAfternoonClockInTime(LocalDateTime.parse("2021-09-01 09:00:00"));
            // DB 操作
            return RestResult.success("补卡成功，类型为下班卡");
        }
        return RestResult.builder().code(-1).msg("服务器繁忙，请联系管理员");
    }

    /**
     * TODO 删除打卡记录
     * @param request 请求报文
     * @param date 日期
     */
    public RestResult<Object> deleteClockIn(HttpServletRequest request, LocalDate date){

        // 用户获取和校验与上面相同

        // 查询指定日期打卡记录，sql 根据传入时间进行指定天查询记录
        ClockInRecord record = userClockInMapper.getOneDayClockInByUserIdAndDate(userId, date);

        if (record == null){
            return RestResult.error("当天不存在记录");
        } else {
            int result = userClockInMapper.deleteById(record.getId());
            // 如果入库失败，则日志记录，并 return
        }
        return RestResult.builder().code(-1).msg("服务器繁忙，请联系管理员");
    }

    /**
     * TODO 查询员工最高连续打卡天数和当前连续打卡天数（这一步可以直接通过sql获取，根据题意排除sql直接获取；）
     * @param userId 用户ID
     */
    public RestResult<Object> getContinuousClockIn(Long userId){
        // 查询出用户所有打卡记录（如果当天打卡了，会产生一条记录，如果数据量还是过大采用分页查询或者多线程分批查询，多线程使用 CallAble 接口）

        // 查询出来的数据，根据创建时间排序（如果ID是long型，并且采用雪花或redis生成，直接根据ID倒叙排序）
        ArrayList<ClockInRecord> list = new ArrayList<ClockInRecord>();

        // 最终结果，当前连续打卡最大天数
        int current = 0;
        // 最终结果，历史连续打卡最大天数
        int history = 0;
        // 某一个时间段连续打卡最大天数
        int someHistory = 0;
        LocalDate now = LocalDate.now();
        int size = list.size();

        // 遍历集合，只需遍历一次
        for (int i = 0; i < size; i++) {
            ClockInRecord record = list.get(i);
            // 创建时间用 localDate 类型保存
            LocalDate currentDate = record.getGmtCreate().toLocalDate();
            // 第一个是当天打卡记录
            if (i == 0){
                if (currentDate.isEqual(now)){
                    current++;
                    someHistory++;
                    continue;
                }
            }
            // 时间差
            Duration duration = Duration.between(list.get(i-1)).getGmtCreate().toLocalDate(), currentDate);
            long l = duration.toDays();
            // 相差一天
            if (l == 1){
                current++;
                someHistory++;
            } else {
                // 如果不连续
                if (someHistory > history){
                    history = someHistory;
                    someHistory = 0;
                }
                someHistory++;
            }
        }

        return RestResult.success(new HashMap<String, Integer>(){{
            put("current", current);
            put("history", history);
        }});
    }

}
